package org.noote.libs.assistant;

import java.util.ArrayList;
import java.util.Locale;

import org.noote.libs.assistant.analyse.AnalyseGrammaticale;
import org.noote.libs.assistant.analyse.Dictionnaire;
import org.noote.libs.assistant.analyse.Grammaire;
import org.noote.libs.assistant.analyse.Phrase;
import org.noote.libs.assistant.analyse.Ponctuation;
import org.noote.libs.assistant.analyse.dictionnaire.Dictionnaire_FR_FR;
import org.noote.libs.assistant.analyse.grammaire.Grammaire_FR_FR;
import org.noote.libs.assistant.analyse.ponctuation.Ponctuation_FR_FR;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.speech.tts.TextToSpeech;
import android.util.Log;

// http://android-developers.blogspot.fr/2009/09/introduction-to-text-to-speech-in.html
// http://code.google.com/p/adk-moto/source/browse/src/com/jmoyer/adk_moto/ADKMoto.java

public class Assistant implements TextToSpeech.OnInitListener {
	
	private static final String TAG = "Assistant";
	
	Assistant_Event _events;
	
	private TextToSpeech _tts;
	
	private SpeechRecognizer _sr;
	private Intent _srIntent;
	
	protected boolean _bListening = false;
	
	protected AnalyseGrammaticale _ag = new AnalyseGrammaticale();
	protected Ponctuation _ponctFR = new Ponctuation_FR_FR();
	protected Dictionnaire _dicoFR = new Dictionnaire_FR_FR();
	protected Grammaire _gramFR = new Grammaire_FR_FR();
	protected Agent _agent = null;
	
	public Assistant(Context cnt, Assistant_Event events, Agent agent)
	{
		this._events = events;
		this._agent = agent;
		
		// TTS Stuff
		_tts = new TextToSpeech(cnt, this);
		if(_tts == null)
		{
			_events.ttsError("Cannot create TextToSpeech object");
		}
		
		// SR Stuff
		if(SpeechRecognizer.isRecognitionAvailable(cnt))
		{
			_sr = SpeechRecognizer.createSpeechRecognizer(cnt);
			if(_sr == null)
			{
				_events.srError("Cannot create SpeechRecognizer object");
				return;
			}
			
			_sr.setRecognitionListener(mRecognitionListener);
			_srIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
			if(_srIntent == null)
			{
				_events.srError("Cannot create RecognizerIntent");
				_sr.destroy();
				_sr = null;
				return;
			}

			_srIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass().getPackage().getName());
			_srIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
			//_srIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 2);
			
			_events.srReady();
		}
		else
		{
			_events.srError("No recognition service available !");
		}
	}
	
   public void close() {
       // Don't forget to shutdown tts!
       if (_tts != null) {
       	_tts.stop();
       	_tts.shutdown();
        _tts = null;       	
       }
       _events.ttsClosed();
       // and rs service 
       if(_sr != null)
       {
    	   _sr.stopListening();
    	   _sr.cancel();
    	   _sr.destroy();
    	   _sr = null;
       }
       _events.srClosed();
   }

   public boolean process(String sText)
   {
	   // fun stuff :)
	   if(_ag.analyse(_ponctFR, _dicoFR, _gramFR, sText))
	   {
		   for(Phrase p : _ag.getPhrases())
		   {
			   String sResponce = _agent.repondre(p);
			   if(sResponce.length()>0)
			   {
				   speak(sResponce);
			   }
		   }
	   }
	   
	   return false;
   }

   @Override
    public void onInit(int status) {
 
        if (status == TextToSpeech.SUCCESS) {
        	_events.ttsReady();
        } else {
            Log.e(TAG, "Initilization Failed!");
            _events.ttsError("Initilization Failed!");
        }	 
    }
   
   private boolean checkTTS()
   {
	   if(_tts == null)
	   {
		   _events.ttsError("Synthesis not available");
		   return false;
	   }
	   return true;
   }
   private boolean checkSR()
   {
	   if(_sr == null)
	   {
		   _events.srError("Recognition not available");
		   return false;
	   }
	   return true;
   }
	
   public boolean startListening()
   {
	   if(!checkSR()) return false;
	   
	   _sr.startListening(_srIntent);
	   _bListening = true;
	   
	   return true;
   }
   public boolean stopListening()
   {
	   if(!checkSR()) return false;
	   
	   _bListening = false;
	   _sr.stopListening();
	   
	   return true;
   }
   public boolean isListening()
   {
	   return _bListening;
   }
   
  
   public boolean setEnglishIn()
   {
	   return setLanguageInByIETF("en-US");
   }

   public boolean setFrenchIn()
   {
	   return setLanguageInByIETF("fr-FR");
   }
   protected boolean setLanguageInByIETF(String sLanguage)
   {
	   if(!checkSR()) return false;
	   
	   // TODO check if language exist in SR engine !
	   
	   _srIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, sLanguage);
	   return true;
   }

   public boolean setEnglishOut()
   {
       return setLanguageOutByLocale(Locale.ENGLISH);
   }

   public boolean setFrenchOut()
   {
       return setLanguageOutByLocale(Locale.FRANCE);
   }
   
   public boolean canLanguageOutByLocale(Locale language)
   {
	   if(!checkTTS()) return false;
	   
	   if(_tts.isLanguageAvailable(language)!=TextToSpeech.LANG_AVAILABLE)
	   {
		   _events.ttsError("This Language is not supported");
		   return false;
	   }
	   
	   return true;
   }

   protected boolean setLanguageOutByLocale(Locale language)
   {
	   if(!checkTTS()) return false;
	   
       int result = _tts.setLanguage(language);
       if (result == TextToSpeech.LANG_MISSING_DATA
               || result == TextToSpeech.LANG_NOT_SUPPORTED) {
    	   Log.e(TAG, "This Language is not supported");
    	   _events.ttsError("This Language is not supported");
           return false;
       }

       return true;
   }

   public boolean  speak(String text) {
	   if(!checkTTS()) return false;
	   
       _tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
       //TODO get speak return and analyse error
       
       return true;
   }
   
   final private RecognitionListener mRecognitionListener = new RecognitionListener()
   {

	@Override
	public void onBeginningOfSpeech() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onBufferReceived(byte[] buffer) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onEndOfSpeech() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onError(int iErr) {
		// TODO Auto-generated method stub
		String sErr = "";
		switch(iErr)
		{
		case SpeechRecognizer.ERROR_AUDIO: sErr = "ERROR_AUDIO, Audio recording error."; break;
		case SpeechRecognizer.ERROR_CLIENT: sErr = "ERROR_CLIENT, Other client side errors."; break;
		case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: sErr = "ERROR_INSUFFICIENT_PERMISSIONS, Insufficient permissions."; break;
		case SpeechRecognizer.ERROR_NETWORK : sErr = "ERROR_NETWORK, Other network related errors."; break;
		case SpeechRecognizer.ERROR_NETWORK_TIMEOUT  : sErr = "ERROR_NETWORK_TIMEOUT, Other network related errors."; break;
		case SpeechRecognizer.ERROR_NO_MATCH : sErr = "ERROR_NO_MATCH, No recognition result matched."; break;
		case SpeechRecognizer.ERROR_RECOGNIZER_BUSY : sErr = "ERROR_RECOGNIZER_BUSY, RecognitionService busy."; break;
		case SpeechRecognizer.ERROR_SERVER : sErr = "SERVER, Server sends error status."; break;
		case SpeechRecognizer.ERROR_SPEECH_TIMEOUT : sErr = "ERROR_SPEECH_TIMEOUT, No speech input ."; break;
		default: sErr = "SR("+Integer.toString(iErr)+"), Unknow error"; break;
		}
		_events.srError(sErr);
	}

	@Override
	public void onEvent(int eventType, Bundle params) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onPartialResults(Bundle partialResults) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onReadyForSpeech(Bundle params) {
	}

	@Override
	public void onResults(Bundle results) {
		// TODO Auto-generated method stub
		// here process data
		ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
		String sHeard = "";
		for(String s : matches)
		{
			if(s != null && s.length()>0)
				sHeard+=s + " ";
		}
		_events.srHeard(sHeard);
		process(sHeard);
	}

	@Override
	public void onRmsChanged(float rmsdB) {
		// TODO Auto-generated method stub
		
	}
   };
}
